package com.ocom.ugcapi.controller;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.ocom.common.constant.WxServiceUrl;
import com.ocom.common.entity.master.EntityWechatAppInfo;
import com.ocom.common.enums.ResultEnum;
import com.ocom.common.request.ugcapi.WxGzhLoginVo;
import com.ocom.common.resp.Result;
import com.ocom.common.utils.CommonUtil;
import com.ocom.common.utils.KeyUtils;
import com.ocom.common.utils.ResultUtil;
import com.ocom.redis.util.RedisUtil;
import com.ocom.ugcapi.client.PayConfigClientService;
import com.ocom.ugcapi.service.LoginService;
import com.ocom.ugcapi.util.Sm2Utils;
import com.ocom.ugcapi.vo.SmsCodeVo;
import com.ocom.ugcapi.vo.SmsLoginVo;
import com.ocom.ugcapi.vo.UgcLoginVo;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Slf4j
@RestController
public class LoginController {

	@Resource
	private RedisUtil redisUtil;

	@Autowired
	private LoginService loginService;

	@Autowired
	PayConfigClientService payConfigClientService;

	// 获取openId (/getOpenId)
	@PostMapping(WxServiceUrl.URL_GetOpenId)
	public Result GetOpenId(@RequestBody Map<String, Object> map) {
		String code = map.get("code").toString();
		String state = map.get("state").toString();
		log.info("获取openId请求参数:{{}}", code);
		return loginService.GetOpenId(code, state);
	}


	@PostMapping(WxServiceUrl.URL_stateParam)
	public Result stateParam(@RequestBody Map<String, Object> map) {
		if(map.get("comId")==null){
			return ResultUtil.info(500,"未传单位id");
		}
		Long comId = Long.valueOf(map.get("comId").toString());
		log.info("获取stateParam请求参数:{{}}", map);
		return loginService.stateParam(comId);
	}

	// 登录(/ugc/login) xcxapi
	@PostMapping(WxServiceUrl.URL_Login)
	public Result Login(@RequestBody UgcLoginVo ugcLoginVo) {
		log.info("登录(/ugc/login)请求参数:{{}}", ugcLoginVo);
		//下载hutool依赖
		String key = "tbk0Xa67cEePvv14g5Pf1MPzIceQMN14"; // 密钥（8 字节）

		String username = ugcLoginVo.getUsername();
		String cardNo = ugcLoginVo.getCardNo();
		String phone = ugcLoginVo.getPhone();
		String password = ugcLoginVo.getPassword();

		if(!CommonUtil.isNull(username)){
			username = HexUtil.decodeHexStr(username);
			username = SecureUtil.des(key.getBytes(StandardCharsets.UTF_8)).decryptStr(username);
		}
		if(!CommonUtil.isNull(cardNo)){
			cardNo = HexUtil.decodeHexStr(cardNo);
			cardNo = SecureUtil.des(key.getBytes(StandardCharsets.UTF_8)).decryptStr(cardNo);
		}
		if(!CommonUtil.isNull(phone)){
			phone = HexUtil.decodeHexStr(phone);
			phone = SecureUtil.des(key.getBytes(StandardCharsets.UTF_8)).decryptStr(phone);
		}
		if(!CommonUtil.isNull(password)){
			password = HexUtil.decodeHexStr(password);
			password = SecureUtil.des(key.getBytes(StandardCharsets.UTF_8)).decryptStr(password);
		}
		ugcLoginVo.setUsername(username);
		ugcLoginVo.setCardNo(cardNo);
		ugcLoginVo.setPhone(phone);
		ugcLoginVo.setPassword(password);

//		System.out.println();
//		System.out.println(HexUtil.encodeHex(password.getBytes(StandardCharsets.UTF_8)));


		return loginService.Login(ugcLoginVo);
	}

	// 退出（/ugc/logout)
	@PostMapping(WxServiceUrl.URL_Logout)
	public Result Logout(@RequestBody Map<String, Object> map) {
		if(map.get("token")==null){
			return ResultUtil.success();
		}
		String token = map.get("token").toString();
		log.info("退出（/ugc/logout)请求参数:{{}}", token);
		return loginService.Logout(token);
	}


	// 登录(/ugc/gzhlogin) 登录获取 公众号Appid 用于跳转 和State md5参数
	@PostMapping(WxServiceUrl.URL_gzhLogin)
	public Result gzhLogin(@RequestBody UgcLoginVo ugcLoginVo) {
		log.info("登录(/ugc/login)请求参数:{{}}", ugcLoginVo);
		return loginService.Login(ugcLoginVo);
	}


	@Autowired
	private HttpServletRequest requestN;

	//get request headers
	private Map<String, String> getHeadersInfo() {
		Map<String, String> map = new HashMap<String, String>();
		Enumeration headerNames = requestN.getHeaderNames();
		while (headerNames.hasMoreElements()) {
			String key = (String) headerNames.nextElement();
			String value = requestN.getHeader(key);
			map.put(key, value);
		}
		return map;
	}

	//注册短信
	@PostMapping(WxServiceUrl.Url_getSmsCode)
	public Result getCode(@Valid @RequestBody SmsCodeVo smsCodeVo) {


		Map<String, String> headers = getHeadersInfo();
		String ipf = headers.get("remoteip");

		log.info("注册短信  I9sffjHO  记录ip 【{}】【{}】【{}】" ,ipf ,headers,smsCodeVo);

		String lockKey = "gzh:smsIp:" + ipf;

		if(!redisUtil.lock(lockKey , 5)){
			return ResultUtil.error(ResultEnum.Err_3114);
		}

		if (smsCodeVo.getPhone() == null || smsCodeVo.getPhone().length() != 11 || !smsCodeVo.getPhone().substring(0, 1).equals("1")) {
			return ResultUtil.error(ResultEnum.Err_3063);
		}

		if(!redisUtil.lock("gzh:smsPhone:" + smsCodeVo.getPhone(), 60)){
			return ResultUtil.error(ResultEnum.Err_3108);
		}

		redisUtil.zAdd("smsLimit:"+smsCodeVo.getPhone(), System.currentTimeMillis() , System.currentTimeMillis());

		Set<Object> rangeByScore = redisUtil.rangeByScore("smsLimit:"+smsCodeVo.getPhone() , System.currentTimeMillis() - 1000l * 600l, System.currentTimeMillis());

		redisUtil.expire("smsLimit:"+smsCodeVo.getPhone(),600l);

		if (rangeByScore != null &&  rangeByScore.size() > 6) {
			return ResultUtil.error(ResultEnum.Err_3109);
		}

		Map<String, Object> map = new HashMap<>();

		map.put("sdkAppId", "1400314290");
		map.put("secretId", "AKIDcLzhN0a8e8eChEnaQG8zpifcabfnu5JX");
		map.put("secretKey", "Kh6VozznPn13ECwSlphN9jCVaRLTPIPa");
		map.put("signName", "广州市鑫澳康科技有限公司");
		map.put("phone", smsCodeVo.getPhone());
		if(smsCodeVo.getType()==1){
			map.put("templateId", "2508963");
		}else{
			map.put("templateId", "2357578");
		}

		try {
			Credential cred = new Credential(map.get("secretId").toString(), map.get("secretKey").toString());

			// 实例化一个http选项，可选，没有特殊需求可以跳过
			HttpProfile httpProfile = new HttpProfile();

			httpProfile.setReqMethod("POST");

			httpProfile.setConnTimeout(60);
			/* 指定接入地域域名，默认就近地域接入域名为 sms.tencentcloudapi.com ，也支持指定地域域名访问，例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com */
			httpProfile.setEndpoint("sms.tencentcloudapi.com");

			ClientProfile clientProfile = new ClientProfile();
			/* SDK默认用TC3-HMAC-SHA256进行签名
			 * 非必要请不要修改这个字段 */
			clientProfile.setSignMethod("HmacSHA256");
			clientProfile.setHttpProfile(httpProfile);

			SmsClient client = new SmsClient(cred, "ap-guangzhou", clientProfile);
			SendSmsRequest req = new SendSmsRequest();

			req.setSmsSdkAppId(map.get("sdkAppId").toString());

			/* 短信签名内容: 使用 UTF-8 编码，必须填写已审核通过的签名 */
			// 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看
			req.setSignName(map.get("signName").toString());
			/* 模板 ID: 必须填写已审核通过的模板 ID */
			// 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
			req.setTemplateId(map.get("templateId").toString());

			/* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致，若无模板参数，则设置为空 */
			//    发送参数

			String code = RandomUtil.randomNumbers(4);
			redisUtil.set("gzh:signCode:" + smsCodeVo.getComId() + ":" + map.get("phone").toString() + ":" + code, code, 300l);
			String[] templateParamSet = {code};
			req.setTemplateParamSet(templateParamSet);

			/* 下发手机号码，采用 E.164 标准，+[国家或地区码][手机号]
			 * 示例如：+8613711112222， 其中前面有一个+号 ，86为国家码，13711112222为手机号，最多不要超过200个手机号 */
			String[] phoneNumberSet = {"+86" + map.get("phone").toString()};
			req.setPhoneNumberSet(phoneNumberSet);

			SendSmsResponse res = client.SendSms(req);

			// 输出json格式的字符串回包
			log.info("SendStatusSet{{}}", SendSmsResponse.toJsonString(res));

		} catch (TencentCloudSDKException e) {
			log.info("TencentCloudSDKException:{{}}", e);
			e.printStackTrace();
		}
		return ResultUtil.success();
	}


	//登录短信
	@PostMapping(WxServiceUrl.Url_getLoginCode)
	public Result Url_getLoginCode(@Valid @RequestBody SmsCodeVo smsCodeVo) {

		if (smsCodeVo.getPhone() == null || smsCodeVo.getPhone().length() != 11 || !smsCodeVo.getPhone().substring(0, 1).equals("1")) {
			return ResultUtil.error(ResultEnum.Err_3063);
		}

		if(!redisUtil.lock("gzh:smsPhone:" + smsCodeVo.getPhone(), 60)){
			return ResultUtil.error(ResultEnum.Err_3108);
		}

		Set<Object> rangeByScore = redisUtil.rangeByScore("smsLimit:"+smsCodeVo.getPhone() , System.currentTimeMillis() - 1000l * 600l, System.currentTimeMillis());

		redisUtil.expire("smsLimit:"+smsCodeVo.getPhone(),600l);

		if (rangeByScore != null &&  rangeByScore.size() > 5) {
			return ResultUtil.error(ResultEnum.Err_3109);
		}

		redisUtil.zAdd("smsLimit:"+smsCodeVo.getPhone(), System.currentTimeMillis() , System.currentTimeMillis());


		Map<String, Object> map = new HashMap<>();

		map.put("sdkAppId", "1400314290");
		map.put("secretId", "AKIDcLzhN0a8e8eChEnaQG8zpifcabfnu5JX");
		map.put("secretKey", "Kh6VozznPn13ECwSlphN9jCVaRLTPIPa");
		map.put("signName", "鑫澳康科技");
		map.put("phone", smsCodeVo.getPhone());
		map.put("templateId", "534057");

		try {
			Credential cred = new Credential(map.get("secretId").toString(), map.get("secretKey").toString());

			// 实例化一个http选项，可选，没有特殊需求可以跳过
			HttpProfile httpProfile = new HttpProfile();

			httpProfile.setReqMethod("POST");

			httpProfile.setConnTimeout(60);
			/* 指定接入地域域名，默认就近地域接入域名为 sms.tencentcloudapi.com ，也支持指定地域域名访问，例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com */
			httpProfile.setEndpoint("sms.tencentcloudapi.com");

			ClientProfile clientProfile = new ClientProfile();
			/* SDK默认用TC3-HMAC-SHA256进行签名
			 * 非必要请不要修改这个字段 */
			clientProfile.setSignMethod("HmacSHA256");
			clientProfile.setHttpProfile(httpProfile);

			SmsClient client = new SmsClient(cred, "ap-guangzhou", clientProfile);
			SendSmsRequest req = new SendSmsRequest();

			req.setSmsSdkAppId(map.get("sdkAppId").toString());

			/* 短信签名内容: 使用 UTF-8 编码，必须填写已审核通过的签名 */
			// 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看
			req.setSignName(map.get("signName").toString());
			/* 模板 ID: 必须填写已审核通过的模板 ID */
			// 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
			req.setTemplateId(map.get("templateId").toString());

			/* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致，若无模板参数，则设置为空 */
			//    发送参数

			String code = RandomUtil.randomNumbers(4);
			redisUtil.set("gzh:signCode:" + smsCodeVo.getComId() + ":" + map.get("phone").toString() + ":" + code, code, 300l);
			String[] templateParamSet = {code};
			req.setTemplateParamSet(templateParamSet);

			/* 下发手机号码，采用 E.164 标准，+[国家或地区码][手机号]
			 * 示例如：+8613711112222， 其中前面有一个+号 ，86为国家码，13711112222为手机号，最多不要超过200个手机号 */
			String[] phoneNumberSet = {"+86" + map.get("phone").toString()};
			req.setPhoneNumberSet(phoneNumberSet);

			SendSmsResponse res = client.SendSms(req);

			// 输出json格式的字符串回包
			log.info("SendStatusSet{{}}", SendSmsResponse.toJsonString(res));

		} catch (TencentCloudSDKException e) {
			log.info("TencentCloudSDKException:{{}}", e);
			e.printStackTrace();
		}
		return ResultUtil.success();
	}


	// 登录(/ugc/gzhlogin) 登录获取 公众号Appid 用于跳转 和State md5参数
	@PostMapping(WxServiceUrl.Url_smsLogin)
	public Result smsLogin(@RequestBody SmsLoginVo smsLoginVo) {
		log.info("登录(/ugc/smsLogin)请求参数:{{}}", smsLoginVo);
		return loginService.Login(smsLoginVo);
	}


	// 3.1 公众号登录(wxgzhLogin)
	@PostMapping(WxServiceUrl.URL_wxgzhLogin)
	public Result wxGzhLoginVo(@RequestBody WxGzhLoginVo wxGzhLoginVo) {
		log.info("公众号登录(wxgzhLogin)请求参数:{{}}", wxGzhLoginVo);
		return loginService.WxGzhLogin(wxGzhLoginVo);
	}


	@PostMapping(WxServiceUrl.URL_lanzhouLogin)
	public Result lanzhouLogin(@RequestBody JSONObject jsonObject2) {

		log.info("兰州银行(lanzhou)  uh9LDu1c  请求参数:{{}}", jsonObject2);

		String code = jsonObject2.getString("code");
		Long comId  = jsonObject2.getLong("comId");

		//兰州  AppPrivateKey 存登录私钥   alipayPublicKey 存签约公钥   alipayAes 存学校名称
		Result<EntityWechatAppInfo> result1 = payConfigClientService.getWxInfo(comId,0l);
		if(result1.getCode()!=200){
			return result1;
		}

		String privateKey = result1.getData().getAppPrivateKey();

		JSONObject jsonObject = null;
		try {
			//解码
			String strCode = URLDecoder.decode(code, "utf-8");
			byte[] decode = Base64.getDecoder().decode(strCode);
			byte[] decrypt = Sm2Utils.decrypt(decode, KeyUtils.createPrivateKey(privateKey));
			String decryptStr = new String(decrypt);
			jsonObject = JSONObject.parseObject(decryptStr);
		}catch (Exception e) {
			log.info("公众号解码异常 kEYFmU85 【{}】",e);
			return ResultUtil.error(ResultEnum.Err_4147);
		}

		//时间判断 TODO
		Long time = System.currentTimeMillis() - jsonObject.getLong("timestamp");
		if (time > 180000l && !jsonObject.getString("userId").equals("123456")) {
			return ResultUtil.error(ResultEnum.Err_3040);
		}

		log.info("兰州银行(lanzhou)  dnD6XmMn  请求参数:{{}}", jsonObject);

		return loginService.lanzhouLogin(comId,result1.getData().getAppid(),jsonObject.getString("userId"),"lanzhou");
	}

}
